﻿using System;
using System.Linq.Expressions;

namespace NMA.Infrastructure.NHibernate.CriteriaExpression
{
    using NMA.Domain.Model;
    using NMA.Domain.Model.Contract;
    using NMA.Infrastructure.NHibernate.CriteriaExpression.Category;
    using NMA.Infrastructure.NHibernate.CriteriaExpression.Category.SearchCategory;
    using NMA.Infrastructure.NHibernate.Container;
    using NMA.Infrastructure.DBC;

    public class CriteriaExpressionFactory : ICriteriaExpressionFactory
    {
        public ISearchChainBuilder SearchBuilder { get; private set; }

        public CriteriaExpressionFactory()
            : this(IoC.GetInstance<ISearchChainBuilder>())
        { }

        internal CriteriaExpressionFactory(ISearchChainBuilder searchBuilder)
        {
            SearchBuilder = searchBuilder;
        }

        public Func<ICategory, bool> CreateCategorySearchCriteria(CategorySearchCriteria criteriaModel)
        {
            Check.Assert(SearchBuilder != null, "SearchChainBuilder is null");
            Check.Assert(criteriaModel != null, "CategorySearchCriteria is null");

            //return new SearchCategoryCriteriaExpression().CreatedCriteriaExpression(criteriaModel, GetSearchCategoryCriteriaType(criteriaModel));

            // replaced with Chain of criteria
            var searchCriteriaType = SearchBuilder.GetSearchCategoryCriteria(criteriaModel);
            return new SearchCategoryCriteriaExpression().CreatedCriteriaExpression(criteriaModel, searchCriteriaType);
        }

        /// <summary>
        ///  This function is only for Unit Testing
        /// </summary>
        /// <param name="criteriaModel">search model</param>
        /// <param name="criteriaType">search criteria type</param>
        /// <returns>the func that contain the search condition</returns>
        public Func<ICategory, bool> CreateCategorySearchCriteria(CategorySearchCriteria criteriaModel, SearchCategoryCriteriaType criteriaType)
        {
            return new SearchCategoryCriteriaExpression().CreatedCriteriaExpression(criteriaModel, criteriaType);
        }

        private SearchCategoryCriteriaType GetSearchCategoryCriteriaType(CategorySearchCriteria criteriaModel)
        {
            SearchCategoryCriteriaType type = SearchCategoryCriteriaType.All;

            if (criteriaModel.Id != null)
            {
                if (!string.IsNullOrEmpty(criteriaModel.Name))
                {
                    if (!string.IsNullOrEmpty(criteriaModel.CreatedUser))
                    {
                        if (criteriaModel.CreatedDate != null)
                        {
                            type = SearchCategoryCriteriaType.All;
                        }
                        else
                        {
                            type = SearchCategoryCriteriaType.Id
                                | SearchCategoryCriteriaType.Name
                                | SearchCategoryCriteriaType.CreatedUser;
                        }
                    }
                    else
                    {
                        if (criteriaModel.CreatedDate != null)
                        {
                            type = SearchCategoryCriteriaType.Id
                                | SearchCategoryCriteriaType.Name
                                | SearchCategoryCriteriaType.CreatedDate;
                        }
                        else
                        {
                            type = SearchCategoryCriteriaType.Id
                                | SearchCategoryCriteriaType.Name;
                        }
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(criteriaModel.CreatedUser))
                    {
                        if (criteriaModel.CreatedDate != null)
                        {
                            type = SearchCategoryCriteriaType.Id
                                | SearchCategoryCriteriaType.CreatedUser
                                | SearchCategoryCriteriaType.CreatedDate;
                        }
                        else
                        {
                            type = SearchCategoryCriteriaType.Id
                                | SearchCategoryCriteriaType.CreatedUser;
                        }
                    }
                    else
                    {
                        if (criteriaModel.CreatedDate != null)
                        {
                            type = SearchCategoryCriteriaType.Id
                                | SearchCategoryCriteriaType.CreatedDate;
                        }
                        else
                        {
                            type = SearchCategoryCriteriaType.Id;
                        }
                    }
                }
            }
            else if (!string.IsNullOrEmpty(criteriaModel.Name))
            {
                if (!string.IsNullOrEmpty(criteriaModel.CreatedUser))
                {
                    if (criteriaModel.CreatedDate != null)
                    {
                        type = SearchCategoryCriteriaType.Name
                            | SearchCategoryCriteriaType.CreatedUser
                            | SearchCategoryCriteriaType.CreatedDate;
                    }
                    else
                    {
                        type = SearchCategoryCriteriaType.Name
                            | SearchCategoryCriteriaType.CreatedUser;
                    }
                }
                else
                {
                    if (criteriaModel.CreatedDate != null)
                    {
                        type = SearchCategoryCriteriaType.Name
                            | SearchCategoryCriteriaType.CreatedDate;
                    }
                    else
                    {
                        type = SearchCategoryCriteriaType.Name;
                    }
                }
            }
            else if (!string.IsNullOrEmpty(criteriaModel.CreatedUser))
            {
                if (criteriaModel.CreatedDate != null)
                {
                    type = SearchCategoryCriteriaType.CreatedUser
                        | SearchCategoryCriteriaType.CreatedDate;
                }
                else
                {
                    type = SearchCategoryCriteriaType.CreatedUser;
                }
            }
            else if (criteriaModel.CreatedDate != null)
            {
                type = SearchCategoryCriteriaType.CreatedDate;
            }

            return type;
        }
    }
}